package com.linchong.concurrency.chapter9;

import lombok.extern.slf4j.Slf4j;

import java.util.stream.Stream;

/**
 * @Author:linchong
 * @CreateTime:2020-01-09 11:27
 * @Description:生产者-消费者v2.0
 */
@Slf4j
public class ProduceConsumerVersion2 {
	private int i = 0;
	final private Object LOCK = new Object();

	//判断是否有产品可供消费
	private volatile boolean isProduced = false;

	public void produce() {
		synchronized (LOCK) {
			if (isProduced) {
				try {
					LOCK.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			} else {
				i++;
				log.info("Produce:{}", i);
				LOCK.notify();
				isProduced = true;
			}
		}
	}

	public void consume() {
		synchronized (LOCK) {
			if (isProduced) {
				log.info("Consume:{}", i);
				LOCK.notify();
				isProduced = false;
			} else {
				try {
					LOCK.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}

	public static void main(String[] args) {
		ProduceConsumerVersion2 pc = new ProduceConsumerVersion2();
		//单个生产者消费者情况
		//singleCondition(pc);

		Stream.of("Produce-1", "Produce-2")
				.forEach(p ->
						new Thread(p) {
							@Override
							public void run() {
								while (true) {
									pc.produce();
								}
							}
						}.start()
				);

		Stream.of("Consumer-1", "Consumer-2")
				.forEach(c ->
						new Thread(c) {
							@Override
							public void run() {
								while (true) {
									pc.consume();
								}
							}
						}.start()
				);

		log.info("wait notify对象规则不知");
		log.info("wait会让出cpu执行权");
		log.info("可能会造成假死状态，原因是notify唤醒对象不知，可能唤醒的对象不知，可能是" +
				"唤醒的是另外一个相同的Consumer或Producer");
		log.info("造成假死的原因是全部wait,");
	}

	private static void singleCondition(ProduceConsumerVersion2 pc) {
		new Thread("Producer-Thread") {
			@Override
			public void run() {
				while (true) {
					try {
						Thread.sleep(1_000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					pc.produce();
				}
			}
		}.start();

		new Thread("Consumer-Thread") {
			@Override
			public void run() {
				while (true) {
					try {
						Thread.sleep(1_000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					pc.consume();
				}
			}
		}.start();
	}

}
